package com.ebo.synframework.synroom.executor.pool;

import com.ebo.synframework.synroom.config.PoolConfig;
import com.ebo.synframework.synroom.executor.SynRoomTask;
import com.ebo.synframework.synroom.executor.TakeTurnsPoolSelector;
import com.ebo.synframework.synroom.executor.ThreadPoolSelector;

public class SynRoomThreadPool implements LogicThreadPool {

    private final SynRoomThreadPool0[] pools;

    private final ThreadPoolSelector selector;
    
    private final int poolNum;
    
    public SynRoomThreadPool(int poolNum, int minThreadNum, int maxThreadNum, int queueTaskNum, String name, ThreadPoolSelector poolSelector) {
        this.poolNum = poolNum;
        pools = new SynRoomThreadPool0[poolNum];
        for (int i = 0; i < poolNum; i++) {
            pools[i] = new SynRoomThreadPool0(minThreadNum, maxThreadNum, queueTaskNum, name + "-" + i + "-");
        }
        poolSelector.setPoolsState(pools);
        this.selector = poolSelector;
    }
    
    
    public SynRoomThreadPool(int poolNum, int minThreadNum, int maxThreadNum, int queueTaskNum, String name) {
        this(poolNum, minThreadNum, maxThreadNum, queueTaskNum, name, new TakeTurnsPoolSelector());
    }
    
    public SynRoomThreadPool(PoolConfig config) {
        this(config.getPoolNum(), config.getMinThreadNum(), config.getMaxThreadNum(), config.getQueueTaskNum(), config.getName());
    }
    
    public PoolState[] getPoolsState() {
        PoolState[] states = new PoolState[pools.length];
        for(int i = 0;i<pools.length;i++) {
            states[i] = new PoolStateWrap(pools[i]);
        }
        return states;
    }
    
    @Override
    public void execute(Runnable runnable) {
        SynRoomTask task = (SynRoomTask) runnable;
        if (poolNum == 1) {
            this.pools[0].execute(task);
        } else {
            int poolIndex = task.getPoolIndex();
            if(poolIndex == -1) {
                poolIndex = this.selector.selectPool();
                if(!task.casPoolIndex(poolIndex)) {
                    poolIndex = task.getPoolIndex();
                    assert poolIndex != -1;
                } 
            } 
            this.pools[poolIndex].execute(task);
        }
    }

}
